/*
 * ArchivoRV.cpp
 *
 *  Created on: 14/04/2013
 *      Author: pato
 */

#include "ArchivoRV.h"

ArchivoRV::ArchivoRV() {
	this->path_Espacios = "biblioteca_espacios.bin";
	this->path_RV = "biblioteca.bin";
	this->listaEspacios = new list<EspaciosRV*>();
	unsigned int offset,tamanyo;
	EspaciosRV* espacio;
	//Abrir Archivo de espacios
	this->archivo_espacios.open("./biblioteca_espacios.bin", fstream::in | fstream::out | fstream::binary);
	if(!this->archivo_espacios.is_open()) {
		cout << "No se encontro el archivo biblioteca_espacios.bin se creara uno vacio" << endl;
		this->archivo_espacios.open("./biblioteca_espacios.bin", fstream::in | fstream::out | fstream::binary | fstream::trunc);
	}
	//CARGAR LISTA DE ESPACIOS LIBRES
	this->archivo_espacios.seekg (0, this->archivo_espacios.end);
	int length = this->archivo_espacios.tellg();
	this->archivo_espacios.seekg (0, this->archivo_espacios.beg);
	if ( length > 4 ) {
		do {
			this->archivo_espacios.read((char*)&offset, sizeof(unsigned int));
			this->archivo_espacios.read((char*)&tamanyo, sizeof(unsigned int));
			espacio = new EspaciosRV(tamanyo,  offset);
			this->listaEspacios->push_back(espacio);
			this->archivo_espacios.peek();
		}while(!this->archivo_espacios.eof());
	}
	this->archivo_espacios.close();
	//Abrir Archivo
	this->archivo.open("./biblioteca.bin", fstream::in | fstream::out | fstream::binary);
	if(!this->archivo.is_open()) {
		cout << "No se encontro el archivo biblioteca.bin se creara uno vacio" << endl;
		this->archivo.open("./biblioteca.bin", fstream::in | fstream::out | fstream::binary | fstream::trunc);
	}
}

ArchivoRV::ArchivoRV(string path) {
	this->path_Espacios = path;
	this->path_RV = path;
	this->path_Espacios += "e.bin";
	this->path_RV += ".bin";
	this->listaEspacios = new list<EspaciosRV*>();
	unsigned int offset,tamanyo;
	EspaciosRV* espacio;
	//Abrir Archivo de espacios
	this->archivo_espacios.open(this->path_Espacios.c_str(), fstream::in | fstream::out | fstream::binary);
	if(!this->archivo_espacios.is_open()) {
		cout << "No se encontro el archivo "<< this->path_Espacios <<" se creara uno vacio." << endl;
		this->archivo_espacios.open(this->path_Espacios.c_str(), fstream::in | fstream::out | fstream::binary | fstream::trunc);
		if(!this->archivo_espacios) {
			cout << "No se se pudo crear el archivo en la ruta indicada." << endl;

		}
	}
	//CARGAR LISTA DE ESPACIOS LIBRES
	this->archivo_espacios.seekg (0, this->archivo_espacios.end);
	int length = this->archivo_espacios.tellg();
	this->archivo_espacios.seekg (0, this->archivo_espacios.beg);
	if ( length > 4 ) {
		do {
			this->archivo_espacios.read((char*)&offset, sizeof(unsigned int));
			this->archivo_espacios.read((char*)&tamanyo, sizeof(unsigned int));
			espacio = new EspaciosRV(tamanyo,  offset);
			this->listaEspacios->push_back(espacio);
			this->archivo_espacios.peek();
		}while(!this->archivo_espacios.eof());
	}
	this->archivo_espacios.close();
	//Abrir Archivo
	this->archivo.open(this->path_RV.c_str() , fstream::in | fstream::out | fstream::binary);
	if(!this->archivo.is_open()) {
		cout << "No se encontro el archivo "<< this->path_RV <<" se creara uno vacio." << endl;
		this->archivo.open(this->path_RV.c_str() , fstream::in | fstream::out | fstream::binary | fstream::trunc);
		if(!this->archivo) {
			cout << "No se se pudo crear el archivo en la ruta indicada." << endl;
		}
	}
}

int ArchivoRV::Escribir(unsigned int largo,const char* registro) {
	unsigned int offset = 0;
	bool hayespacio = false;
	EspaciosRV* espacio = NULL;
	std::list<EspaciosRV*>::const_iterator it;
	for (it = this->listaEspacios->begin(); it != this->listaEspacios->end(); ++it) {
		if(!hayespacio) {
			espacio = (EspaciosRV*) *it;
			if (espacio->getTamanyo() >= largo + 4) {
					hayespacio = true;
					it++;
					this->listaEspacios->remove(espacio);
			}
		}
	}
	//SI no se encontro espacio libre se va al final
	if (!hayespacio) {
		this->archivo.seekg (0, this->archivo.end);
		int length = this->archivo.tellg();
		this->archivo.seekg (0, this->archivo.beg);
		if (length > 4) {
			this->archivo.seekg(0, this->archivo.end);
			offset = this->archivo.tellg();
		} else {
			this->archivo.seekg(0, this->archivo.beg);
			offset = this->archivo.tellg();
		}
	} else {
		if (espacio->getTamanyo() - largo - 4> 0) {
			EspaciosRV* espacio2 = new EspaciosRV(espacio->getTamanyo()-largo-4, espacio->getOffset() + largo + 4);
			this->listaEspacios->push_back(espacio2);
		}
		this->ActualizarEspacios();
		offset = espacio->getOffset();
		this->archivo.seekg(offset);
		delete(espacio);
	}
	this->archivo.write((char*)&largo, sizeof(unsigned int));
	this->archivo.write(registro, largo);
	this->archivo.flush();
	//DEVOLVER OFFSET
	return offset;
}

int ArchivoRV::Leer(int offset, char* registro) {
	unsigned int largo = 0;
	char *cancion= (char*) malloc(MB1 + 100);
	this->archivo.seekg(0, ios_base::end);
	if(archivo.tellg() == 0) {// no hay ningun registro
		return -1;
	}
	this->archivo.seekg(offset);
	this->archivo.read((char*)&largo, sizeof(unsigned int));
	this->archivo.read(cancion,largo);
	for (unsigned int i = 0; i <= largo; i++) {
		registro[i] = cancion[i];
	}
	free(cancion);
	return largo;
}

int ArchivoRV::Borrar(unsigned int offset) {
	unsigned int largo = 0;
	this->archivo.seekg(offset);
	this->archivo.read((char*)&largo, sizeof(unsigned int));
	EspaciosRV* espacio = new EspaciosRV(largo+4,offset);
	this->listaEspacios->push_back(espacio);
	this->ActualizarEspacios();
	return 0;
}

int ArchivoRV::ActualizarEspacios() {
	unsigned int offset;
	unsigned int tamanyo;
	this->archivo_espacios.open(this->path_Espacios.c_str(), fstream::in | fstream::out | fstream::binary  | fstream::trunc);
	if(!this->archivo_espacios.is_open()) {
		cout << "No se encontro el archivo " <<this->path_Espacios << endl;
		if(!this->archivo_espacios.is_open()) { return -1 ;}
	}
	this->archivo_espacios.seekg(0, this->archivo_espacios.beg);
	EspaciosRV* espacio = NULL;
	std::list<EspaciosRV*>::const_iterator it;
	for (it = this->listaEspacios->begin(); it != this->listaEspacios->end(); ++it) {
		espacio = (EspaciosRV*) *it;
		offset = espacio->getOffset();
		tamanyo = espacio->getTamanyo();
		this->archivo_espacios.write((char*)&offset, sizeof(unsigned int));
		this->archivo_espacios.write((char*)&tamanyo, sizeof(unsigned int));
	}
	this->archivo_espacios.flush();
	this->archivo_espacios.close();
	return 0;
}

ArchivoRV::~ArchivoRV() {
	this->archivo.close();
	std::list<EspaciosRV*>::const_iterator it;
	this->ActualizarEspacios();
	for (it = this->listaEspacios->begin(); it != this->listaEspacios->end(); ++it) {
		EspaciosRV* espacio = *it;
		delete(espacio);
	}
	this->listaEspacios->clear();
	delete this->listaEspacios;
}
